package com.train.mgr.modules.biz.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.train.mgr.config.thread.AsyncExecutors;
import com.train.mgr.modules.biz.dto.response.*;
import com.train.mgr.modules.biz.entity.InterfaceLog;
import com.train.mgr.modules.biz.entity.Lesson;
import com.train.mgr.modules.biz.entity.LessonUserExercise;
import com.train.mgr.modules.biz.service.*;
import com.train.mgr.modules.biz.thirdparty.client.VoiceAnalyzeClient;
import com.train.mgr.modules.biz.utils.Mp4ToImageList;
import com.train.mgr.modules.biz.utils.Mp4ToWavAdaptive;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.*;


@Slf4j
@Service("IAnalysisCalService")
public class AnalysisCalServiceImpl implements IAnalysisCalService {

    @Autowired
    private VoiceAnalyzeClient voiceAnalyzeClient;
    @Autowired
    private IAccuracyService accuracyService; //准确度
    @Autowired
    private IFluencyService fluencyService;//流畅度
    @Autowired
    private ICompletenessService completenessService;//完整度
    @Autowired
    private IConfidenceService confidenceService; //自信度
    @Autowired
    private ILessonService lessonService;
    @Autowired
    private IxfyunLfasrClientService ixfyunLfasrClientService;
    @Autowired
    private IInterfaceLogService interfaceLogService;

    @Value("${file.upload-folder}")
    private String uploadFolder;

    @Value("${train.file.url}")
    private String fileVisitUrl;

//    private final ThreadPoolTaskExecutor executor;
//
//    public AnalysisCalServiceImpl(@Qualifier("taskExecutor") ThreadPoolTaskExecutor executor) {
//        this.executor = executor;
//    }

    @Override
    public AudioEvalDto getCalScoreMap(LessonUserExercise lessonUserExercise, String videoFilePath) {
        long start = System.currentTimeMillis();
        Long exerciseId = lessonUserExercise.getId();
        Long lessonId = lessonUserExercise.getLessonId();
        Long audioDuration = Long.valueOf(lessonUserExercise.getUseTime());

        String videoFullPath = uploadFolder + videoFilePath;
        String wavFullPath = videoFullPath.replaceAll("\\.mp4$", ".wav");
        File videoFile = new File(videoFullPath);
        File wavFile = new File(wavFullPath);

        AudioEvalDto dto = new AudioEvalDto();

        /* ---------- 1. 并行：MP4→WAV + 抽帧（IO） ---------- */
        CompletableFuture<Boolean> wavFuture =
                CompletableFuture.supplyAsync(() -> Mp4ToWavAdaptive.convert(videoFile, wavFile), AsyncExecutors.IO);

        CompletableFuture<List<String>> imageFuture =
                CompletableFuture.supplyAsync(() -> Mp4ToImageList.mp4ConvertImagesOld(videoFile, videoFullPath, audioDuration, 10, "jpg"), AsyncExecutors.IO);

        /* ---------- 2. 串行：等 wav → 转写 → 分析（IO） ---------- */
        CompletableFuture<AudioTextRespVo> textFuture =
                wavFuture.thenCompose(ok -> ok
                        ? CompletableFuture.supplyAsync(() -> ixfyunLfasrClientService.getAudioText(exerciseId, wavFullPath), AsyncExecutors.IO)
                        : CompletableFuture.supplyAsync(() -> {
                    throw new RuntimeException("wav 转换失败");
                }, AsyncExecutors.IO));

        CompletableFuture<AiAnalyzeResp> analyzeFuture =
                textFuture.thenCompose(txt -> CompletableFuture.supplyAsync(() -> {
                    Lesson lesson = lessonService.getById(lessonId);
                    String ref = completenessService.getFABEString(lesson);
                    return voiceAnalyzeClient.readAnalyze(wavFile, ref, txt.getAudioText(), "", 2.0f, -40.0f);
                }, AsyncExecutors.IO));

        /* ---------- 3. 并行：等分析 → 5 维评分（CPU） ---------- */
        CompletableFuture<BigDecimal> completenessFuture =
                analyzeFuture.thenCompose(resp -> CompletableFuture.supplyAsync(() -> completenessService.calCompletenessScore(resp.getWer()), AsyncExecutors.CPU));

        CompletableFuture<KeywordMatchResult> accuracyFuture =
                analyzeFuture.thenCompose(resp -> textFuture.thenApply(txt ->
                        accuracyService.calAccuracyScore(exerciseId, lessonService.getById(lessonId), txt)));

        CompletableFuture<ScoreAndWenAnVo> fluencyFuture =
                analyzeFuture.thenCompose(resp -> CompletableFuture.supplyAsync(() -> fluencyService.calFluencyScore(audioDuration, resp), AsyncExecutors.CPU));

        CompletableFuture<ScoreAndWenAnVo> confidenceFuture =
                analyzeFuture.thenCompose(resp -> imageFuture.thenApply(images ->
                        confidenceService.calConfidenceScore(exerciseId, audioDuration, resp, images, wavFullPath, textFuture.getNow(null).getAudioText())));

        /* ---------- 4. 硬超时等待（JDK8 无 orTimeout） ---------- */
        final CountDownLatch latch = new CountDownLatch(1);
        CompletableFuture.allOf(textFuture, analyzeFuture, completenessFuture, accuracyFuture, fluencyFuture, confidenceFuture)
                .thenRun(latch::countDown);

//        try {
//            boolean finished = latch.await(60, TimeUnit.SECONDS);
//            if (!finished) {
//                log.error("分析任务总超时（>60s）");
//                return dto;
//            }
//        } catch (InterruptedException e) {
//            Thread.currentThread().interrupt();
//            log.error("等待被中断", e);
//            return dto;
//        }

        /* ---------- 5. 组装结果 ---------- */
        String aiAnalyzeResult = null;
        try {
            AudioTextRespVo textResp = textFuture.get();
            AiAnalyzeResp resp = analyzeFuture.get();
            aiAnalyzeResult = JSONObject.toJSONString(resp);;

            dto.setAudioDuration(textResp.getAudioDuration());   // 修正字段
            dto.setAudioText(textResp.getAudioText());

            // 1. 完整度
            dto.setCompletenessScore(completenessFuture.get());
            dto.setCompletenessScoreDesc(getScoreDesc(dto.getCompletenessScore()));
            dto.setCompletenessWenAn(completenessService.getQwenModelFeedback(lessonService.getById(lessonId).getSalesLanguage(), textResp.getAudioText()));
            log.info("**********************练习ID:{}, 完整度得分:{}",exerciseId,dto.getCompletenessScore());

            // 2. 准确度
            KeywordMatchResult acc = accuracyFuture.get();
            dto.setAccuracyScore(acc.getAccuracyScore());
            dto.setAccuracyScoreDesc(getScoreDesc(acc.getAccuracyScore()));
            dto.setAccuracyWenAn(accuracyService.getAccuracyReport(acc.getAccuracyScore(), acc.getMissList()));
            log.info("*********************练习ID:{}, 准确度分:{}",exerciseId,dto.getAccuracyScore());

            // 4. 流畅度（含语速音量）
            ScoreAndWenAnVo flu = fluencyFuture.get();
            dto.setFluencyScore(flu.getScore());
            dto.setFluencyScoreDesc(getScoreDesc(flu.getScore()));
            dto.setFluencyWenAn(flu.getWenAn());
            dto.setWpmAvgVoiced(flu.getWpmAvgVoiced());
            log.info("********************练习ID:{},  流畅度分:{}",exerciseId,dto.getFluencyScore());

            SpeedAndVolumeVo sv = flu.getSpeedAndVolumeVo();
            dto.setSpeedVolumeScore(sv.getSpeedAndVolumeScore());
            dto.setSpeedVolumeScoreDesc(getScoreDesc(sv.getSpeedAndVolumeScore()));
            dto.setSpeedVolumeWenAn(fluencyService.getSpeedQwenModel(sv));
            log.info("********************练习ID:{},  语速音量:{}",exerciseId,dto.getSpeedVolumeScore());

            // 5. 自信度
            ScoreAndWenAnVo conf = confidenceFuture.get();
            dto.setConfidenceScore(conf.getScore());
            dto.setConfidenceScoreDesc(getScoreDesc(conf.getScore()));
            dto.setConfidenceWenAn(conf.getWenAn());
            log.info("********************练习ID:{},  自信度分:{}",exerciseId,dto.getConfidenceScore());

        } catch (Exception ex) {
            log.error("组装结果异常", ex);
        } finally {
            long myCost = (System.currentTimeMillis() - start) / 1000;
            log.info("getCalScoreMap 总耗时: {} s", myCost);
            final String aiResultFinal = aiAnalyzeResult;
            // 异步写日志，不阻塞返回
            CompletableFuture.runAsync(() -> {
                InterfaceLog log = new InterfaceLog();
                log.setInterfaceType("朗读流畅性评估API");
                log.setResposeResult(aiResultFinal);
                log.setRequestParam("略");
                log.setExerciseId(exerciseId);
                log.setRequestSpeedTime(myCost + " 毫秒");
                interfaceLogService.save(log);
            }, AsyncExecutors.IO);
        }
        return dto;
    }

    /**
     * 对外唯一入口：多线程计算 5 维度
     * lessonUserExercise: 提交练习作品对象
     * videoFilePath：视频文件

    @Override
    public AudioEvalDto getCalScoreMap(LessonUserExercise lessonUserExercise,
                                       String videoFilePath) {
        Long exerciseId = lessonUserExercise.getId();
        Long lessonId = lessonUserExercise.getLessonId();
        Long audioDuration = Long.parseLong(lessonUserExercise.getUseTime());//音频时长
        long start =  System.currentTimeMillis();
        log.info("getCalScoreMap lessonUserExercise:{}",JSONUtil.toJsonStr(lessonUserExercise));
       // log.info("getCalScoreMap imagePathList:{}", JSONUtil.toJsonStr(imagePathList));
        log.info("getCalScoreMap videoFilePath:{}",videoFilePath);
        String videoFullPath = uploadFolder + videoFilePath;
        String wavFullPath   = videoFullPath.replaceAll("\\.mp4$", ".wav");
        File videoFile = new File(videoFullPath);
        File wavFile = new File(wavFullPath);
        //把mp4文件转wav音频文件
        long t = System.currentTimeMillis();
        boolean ok = Mp4ToWavAdaptive.convert(videoFile,wavFile);
        long cost = System.currentTimeMillis() - t;
        log.info(ok ? "转换成功" : "转换失败");
        log.info("Mp4转wav文件-耗时: {} s", cost / 1000.0);

        //视频-图片抽帧
        List<String> imagesPathList = Mp4ToImageList.mp4ConvertImagesOld(videoFile,videoFullPath,audioDuration, 20, "jpg");
        // 组装 DTO
        AudioEvalDto dto = new AudioEvalDto();
        String logResponse = "";
        String logRequest = "";
        double aiAnalyzeRespCost = 0;
        try{
            AudioTextRespVo textResp = ixfyunLfasrClientService.getAudioText(exerciseId,wavFullPath);
            Lesson lesson = lessonService.getById(lessonId);

            String transcriptRef = completenessService.getFABEString(lesson);
            //log.info("参考文本：transcriptRef: {} ",transcriptRef);
            logRequest = "wavPath:【"+fileVisitUrl+ wavFullPath.replaceAll(uploadFolder, "")+"】，transcriptRef:【"+transcriptRef+"】，transcriptHyp【"+textResp.getAudioText()+"]";
            long aiAnalyzeRespCostStart =  System.currentTimeMillis();
            AiAnalyzeResp resp = voiceAnalyzeClient.readAnalyze(wavFile, transcriptRef, textResp.getAudioText(), "", 2.0f, -40.0f);
            aiAnalyzeRespCost = System.currentTimeMillis() - aiAnalyzeRespCostStart;
            logResponse = JSONUtil.toJsonStr(resp);

           // log.info("************** getCalScoreMap resp:{}", JSONUtil.toJsonStr(resp));
            log.info("************** 讯飞转码结果:{}", JSONUtil.toJsonStr(textResp));
            // 并发计算
            log.info("************** 多线程处理开始.....");
            CompletableFuture<BigDecimal> completenessFuture =
                    CompletableFuture.supplyAsync(() -> completenessService.calCompletenessScore(resp.getWer()), executor);

            CompletableFuture<KeywordMatchResult> accuracyFuture =
                    CompletableFuture.supplyAsync(() -> accuracyService.calAccuracyScore(exerciseId,lesson, textResp), executor);

            CompletableFuture<ScoreAndWenAnVo> fluencyFuture =
                    CompletableFuture.supplyAsync(() -> fluencyService.calFluencyScore(audioDuration, resp), executor);

            CompletableFuture<ScoreAndWenAnVo> confidenceFuture =
                    CompletableFuture.supplyAsync(() -> confidenceService.calConfidenceScore(
                            exerciseId,audioDuration,resp,imagesPathList,wavFullPath, textResp.getAudioText()), executor);

            // 等待全部完成
            CompletableFuture.allOf(completenessFuture, accuracyFuture,fluencyFuture, confidenceFuture).join();
            log.info("************** getCalScoreMap 等待全部完成.....");
            dto.setAudioDuration(textResp.getAudioDuration());
            dto.setAudioText(textResp.getAudioText());

            // 1. 完整度
            dto.setCompletenessScore(completenessFuture.get());
            dto.setCompletenessScoreDesc(getScoreDesc(dto.getCompletenessScore()));
            dto.setCompletenessWenAn(completenessService.getQwenModelFeedback(lesson.getSalesLanguage(), textResp.getAudioText()));
            log.info("********************** 完整度得分:{}",dto.getCompletenessScore());

            // 2. 准确度
            KeywordMatchResult acc = accuracyFuture.get();
            dto.setAccuracyScore(acc.getAccuracyScore());
            dto.setAccuracyScoreDesc(getScoreDesc(acc.getAccuracyScore()));
            dto.setAccuracyWenAn(accuracyService.getAccuracyReport(acc.getAccuracyScore(), acc.getMissList()));
            log.info("********************* 准确度分:{}",dto.getAccuracyScore());

            // 4. 流畅度（包括流畅度的逻辑）
            ScoreAndWenAnVo flu = fluencyFuture.get();
            dto.setFluencyScore(flu.getScore());
            dto.setFluencyScoreDesc(getScoreDesc(flu.getScore()));
            dto.setFluencyWenAn(flu.getWenAn());
            log.info("******************** 流畅度分:{}",dto.getFluencyScore());

            // 3. 语速音量 --- 来自流畅度。
            SpeedAndVolumeVo sv = flu.getSpeedAndVolumeVo();
            dto.setSpeedVolumeScore(sv.getSpeedAndVolumeScore());
            dto.setSpeedVolumeScoreDesc(getScoreDesc(sv.getSpeedAndVolumeScore()));
            dto.setSpeedVolumeWenAn(fluencyService.getSpeedQwenModel(sv));
            log.info("******************** 语速音量:{}",dto.getSpeedVolumeScore());

            // 5. 自信度
            ScoreAndWenAnVo conf = confidenceFuture.get();
            dto.setConfidenceScore(conf.getScore());
            dto.setConfidenceScoreDesc(getScoreDesc(conf.getScore()));
            dto.setConfidenceWenAn(conf.getWenAn());
            log.info("******************** 自信度分:{}",dto.getConfidenceScore());
        }catch (Exception ex){
            log.error("error,",ex);
            //ex.printStackTrace();
            return dto;
        }finally {
            log.info("**************************************************************");
            log.info("统计5个维度的分数完成，返回结果是:{}", JSONObject.toJSONString(dto));
            long myCost = (System.currentTimeMillis() - start ) / 1_000;
            log.info(" getCalScoreMap 方法计算维度分数总耗时: " + myCost + " s");
            log.info("**************************************************************");

            InterfaceLog interfaceLog = new InterfaceLog();
            interfaceLog.setInterfaceType("朗读流畅性评估API");
            interfaceLog.setResposeResult(logResponse);
            interfaceLog.setRequestParam(logRequest);
            interfaceLog.setExerciseId(exerciseId);
            interfaceLog.setRequestSpeedTime(aiAnalyzeRespCost+" 毫秒");
            interfaceLogService.save(interfaceLog);
        }
        return dto;
    }*/

    /**
     * 根据分数返回对应描述
     * @param score 0~100 的分数（BigDecimal）
     * @return 描述字符串
     */
    private String getScoreDesc(BigDecimal score) {
        if (score == null) return "需改进";

        int val = score.intValue();
        if (val < 60) return "需改进";
        if (val <= 69) return "一般";
        if (val <= 85) return "良好";
        if (val <= 95) return "优秀";
        return "卓越";
    }
}
